package net.sourceforge.javaocr.ocrPlugins.neuralNetOCR;

import java.awt.Frame;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;

import javax.imageio.ImageIO;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;

import net.sourceforge.javaocr.gui.neuralNetOCR.TrainingImageSpec;

import org.encog.ml.data.MLData;
import org.encog.ml.data.MLDataSet;
import org.encog.ml.data.basic.BasicMLData;
import org.encog.ml.data.basic.BasicMLDataPair;
import org.encog.ml.data.basic.BasicMLDataSet;
import org.encog.neural.som.SOM;
import org.encog.neural.som.training.clustercopy.SOMClusterCopyTraining;

/**
 * OCR: Main form that allows the user to interact with the OCR application.
 */
public class OCR extends JFrame {
	/**
	 * Serial id for this class.
	 */
	private static final long serialVersionUID = -6779380961875907013L;

	/**
	 * The downsample width for the application.
	 */
	static final int DOWNSAMPLE_WIDTH = 35;

	/**
	 * The down sample height for the application.
	 */
	static final int DOWNSAMPLE_HEIGHT = 35;
	
	/**
	 * The letters that have been defined.
	 */
	private DefaultListModel letterListModel = new DefaultListModel();

	/**
	 * The neural network.
	 */
	private SOM net;

	private OCRScannerNeuralNet ocrScannerNeural;

	private ArrayList<TrainingImageSpec> imagenesEntrenamiento;
	/**
	 * The constructor.
	 */
	public OCR () {
		
	}
	/**
	 * Run method for the background training thread.
	 */
	public void trainSOM() {
		try {
			final int inputNeuron = OCR.DOWNSAMPLE_HEIGHT * OCR.DOWNSAMPLE_WIDTH;
			final int outputNeuron = this.ocrScannerNeural.getLetterListModel().size();

			final MLDataSet trainingSet = new BasicMLDataSet();
			for (int t = 0; t < this.ocrScannerNeural.getLetterListModel().size(); t++) {
				
				int idx = 0;
				final SampleData ds = (SampleData) this.ocrScannerNeural.getLetterListModel().getElementAt(t);
				final MLData item = new BasicMLData(inputNeuron);
				for (int y = 0; y < ds.getHeight(); y++) {
					for (int x = 0; x < ds.getWidth(); x++) {
						item.setData(idx++, ds.getData(x, y) ? .5 : -.5);
					}
				}
				System.out.println("Entreno la letra: " + ds.letter);
					for (int y = 0; y < ds.getHeight(); y++) {
						for (int x = 0; x < ds.getWidth(); x++) {
							System.out.print(ds.getData(x, y) ? '*' : ' ');
						}
						System.out.println();
					}
				trainingSet.add(new BasicMLDataPair(item, null));
			}


				

			
			this.net = new SOM(inputNeuron,outputNeuron);
			this.net.reset();

			SOMClusterCopyTraining train = new SOMClusterCopyTraining(this.net,trainingSet);
			
			train.iteration();

	
			} catch (final Exception e) {
				e.printStackTrace();
			}

	}

	public void init(ArrayList<TrainingImageSpec> imgs) {
		this.ocrScannerNeural = new OCRScannerNeuralNet();
		this.imagenesEntrenamiento = new ArrayList<TrainingImageSpec>();
		for (TrainingImageSpec trainingImageSpec : imgs) {
			File file = new File(trainingImageSpec.getFileLocation());
			if (file.isDirectory()) {
				File[] listFiles = file.listFiles();
				for (File file2 : listFiles) {
					if (file2.exists() && file2.isFile()) {
						TrainingImageSpec trainingImg = new TrainingImageSpec();
						trainingImg.setFileLocation(file2.getAbsolutePath());
						
						int chr = file2.getName().substring(file2.getName().indexOf("_") + 1, file2.getName().indexOf(".")).charAt(0);
						CharacterRange chR = new CharacterRange(chr, chr);
						trainingImg.setCharRange(chR);
						this.imagenesEntrenamiento.add(trainingImg);
					}
				}
			} else {
				this.imagenesEntrenamiento.add(trainingImageSpec);
			}
		}
	}

	public void training() throws Exception {
		//Genero la lista de letras En el OCRScannerNeural 
		ocrScannerNeural.setLetterListModel(getTrainingImageNeuralHashMap());
		trainSOM();
		ocrScannerNeural.setNet(this.net);
	}
	
	public String scan(String targImageLoc) throws Exception {
		BufferedImage targetImage = ImageIO.read(new File(targImageLoc));
		return ocrScannerNeural.scan(targetImage, 0, 0, 0, 0, null);
	}

	
	private DefaultListModel getTrainingImageNeuralHashMap() throws Exception {
    	net.sourceforge.javaocr.ocrPlugins.neuralNetOCR.TrainingImageLoader loader = new net.sourceforge.javaocr.ocrPlugins.neuralNetOCR.TrainingImageLoader();
        HashMap<Character, ArrayList<TrainingImageNeural>> trainingImages = new HashMap<Character, ArrayList<TrainingImageNeural>>();
        Frame frame = new Frame();

        for (int i = 0; i < this.imagenesEntrenamiento.size(); i++)
        {
            loader.load(
                    frame,
                    this.imagenesEntrenamiento.get(i).getFileLocation(),
                    this.imagenesEntrenamiento.get(i).getCharRange(),
                    trainingImages);
        }
        
        return loader.getLetterListModel();
    }

}
